package com.yuyou.fn.settlement.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.github.wens.framework.service.impl.SuperServiceImpl;
import com.github.wens.mybatisplus.examples.Example;
import com.github.wens.mybatisplus.toolkit.IdWorker;
import com.yuyou.fn.common.constant.Constants;
import com.yuyou.fn.common.exception.BusException;
import com.yuyou.fn.common.rocketmq.Producer;
import com.yuyou.fn.common.service.IEmailService;
import com.yuyou.fn.common.service.ISiteConfigService;
import com.yuyou.fn.common.util.*;
import com.yuyou.fn.settlement.entity.PayOrder;
import com.yuyou.fn.settlement.mapper.PayOrderMapper;
import com.yuyou.fn.settlement.service.IPayOrderService;
import com.yuyou.fn.settlement.vo.PreparePayResultVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 *
 * PayOrder 表数据服务层接口实现类
 *
 */
@Service
public class PayOrderServiceImpl extends SuperServiceImpl<PayOrderMapper, PayOrder,Long> implements IPayOrderService ,InitializingBean {

    private static final Logger log = LoggerFactory.getLogger(PayOrderServiceImpl.class) ;

    @Resource
    private ISiteConfigService siteConfigService ;

    @Resource
    private Producer producer;

    private String appId;

    private String appKey;

    @Resource
    private IEmailService emailService;


    @Value("${dev.env}")
    private boolean dev;

    private String payCreateOrderUrl;

    private String merCode ;

    @Override
    public void afterPropertiesSet() throws Exception {
        appId = siteConfigService.getConfigValueFromCache("zy_pay_center_app_id");
        appKey = siteConfigService.getConfigValueFromCache("zy_pay_center_app_key");
        payCreateOrderUrl = siteConfigService.getConfigValueFromCache("zy_pay_center_create_order_url");
        merCode = siteConfigService.getConfigValueFromCache("zy_pay_center_create_mer_code");
    }

    @Override
    public PreparePayResultVo preparePay(String userId , Long busId , String busType , BigDecimal amount , String orderName , String orderContent , String returnUrl ) {

        Date now = TimeUtils.now() ;
        PayOrder payOrder = new PayOrder();
        Long orderId  = IdWorker.getId() ;


        String orderAmount = BigDecimals.formatBigDecimal(amount.multiply(new BigDecimal(100) ), "0" );

        Map<String, String> params = new HashMap<>();
        params.put("id", orderId.toString());
        params.put("version", "3.0");
        params.put("appId", appId);
        params.put("orderId", String.valueOf(orderId) );
        params.put("amount",dev? "1": orderAmount);
        params.put("orderName", orderName);
        params.put("orderContent", orderContent);
        params.put("orderCreateTime", String.valueOf(now.getTime()));
        params.put("userId", userId );
        params.put("returnUrl", returnUrl);// 支付成功后的页面
        params.put("merCode",merCode);

        String resultJson = createOrderOnPayCenter(params);

        log.info("createOrderOnPayCenter({}) return：{}", JSONObject.toJSONString(params), resultJson);

        JSONObject ret = JSONObject.parseObject(resultJson);

        if (ret.containsKey("result")) {
            JSONObject result  = ret.getJSONObject("result");
            payOrder.setPayOrderId(orderId);
            payOrder.setAmount(amount);
            payOrder.setBusId(busId);
            payOrder.setBusType(busType);
            payOrder.setCreateTime(TimeUtils.now());
            payOrder.setUpdateTime(payOrder.getCreateTime());
            payOrder.setStatus(Constants.PAY_ORDER_STATUS_OF_NOT_PAY);
            payOrder.setSubject(orderName);
            payOrder.setBody(orderContent);
            payOrder.setChargeId(result.getString("payOrderId"));
            insertSelective(payOrder);
            PreparePayResultVo preparePayResultVo=new PreparePayResultVo();
            preparePayResultVo.setPayUrl(result.getString("counterUrl"));
            preparePayResultVo.setPayOrderId(orderId);
            return preparePayResultVo;
        } else {
            throw new BusException(ret.getJSONObject("error").getString("message"));
        }


    }
    public String createOrderOnPayCenter(Map<String,String> submitParams) {
        submitParams.put("sign",TmsPaySignUtils.sign(submitParams, appKey));
        log.info("Submit params: " + submitParams.toString());
        try {
            String content = HttpClientUtil2.post(payCreateOrderUrl, submitParams);
            return content;
        } catch (Exception e) {
            log.error("create order fail", e);
            throw new BusException("支付中心生成订单失败");
        }

    }

    @Override
    public void callback(String id, String version, String appId, Long orderId, String payOrderId, int payStatus, String attach, String firstSucTrxId, String firstSucChannelId, long firstSucNotifyTime, String sign,String thirdTrxNo,String payPrx,String payMode,String terminal) {
        Map<String, String> params = new HashMap<>();
        params.put("id", id);
        params.put("version", version);
        params.put("appId", appId);
        params.put("orderId", String.valueOf(orderId));
        params.put("payOrderId", payOrderId);
        params.put("payStatus", String.valueOf(payStatus));
        params.put("attach", attach);
        params.put("firstSucTrxId", firstSucTrxId);
        params.put("firstSucChannelId", firstSucChannelId);
        params.put("firstSucNotifyTime", String.valueOf(firstSucNotifyTime));

        params.put("thirdTrxNo", String.valueOf(thirdTrxNo));
        params.put("payPrx", String.valueOf(payPrx));
        params.put("payMode", String.valueOf(payMode));
        params.put("terminal", String.valueOf(terminal));
        log.info("callbackParams:"+params.toString());

        if (TmsPaySignUtils.sign(params, appKey).equalsIgnoreCase(sign)) {

            if(payStatus == 1 ){//支付成功
                String channel  = firstSucChannelId;
                if(firstSucChannelId.equalsIgnoreCase("wx")){
                    channel = "wx_pub";
                }else if(firstSucChannelId.equalsIgnoreCase("alipay")){
                    channel = "alipay_wap" ;
                }
                updateOrderStatusAfterSuccessPay(payOrderId , Long.valueOf( orderId ) ,thirdTrxNo , channel );
            }

        } else {
            throw new BusException("Invalid sign");
        }
    }


    private void updateOrderStatusAfterSuccessPay(String chargeId, Long orderId, String transactionNo , String channel ) {
        PayOrder order = findById(orderId);


        PayOrder payOrder = new PayOrder();
        payOrder.setChannel(channel);
        payOrder.setStatus(Constants.PAY_ORDER_STATUS_OF_PAID);
        payOrder.setChannelTransactionNo(transactionNo);
        Example<PayOrder> example = PayOrder.createExample();
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("payOrderId" , orderId ).andEqualTo("chargeId" ,chargeId ).andEqualTo("status",order.getStatus() );

        boolean s = updateSelectiveByExample(payOrder, example );

        if(s){
            order.setChannel(channel);
            order.setChannelTransactionNo(transactionNo);
            order.setStatus(Constants.PAY_ORDER_STATUS_OF_PAID);
            sendPaySuccessEvent(transactionNo, order);
        }
    }

    private void sendPaySuccessEvent(String transactionNo, PayOrder order) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("payOrderId" , order.getPayOrderId() );
        jsonObject.put("busId",order.getBusId());
        jsonObject.put("busType",order.getBusType().trim());
        jsonObject.put("amount" ,order.getAmount());
        jsonObject.put("transactionNo" ,transactionNo );
        jsonObject.put("channel" ,order.getChannel());

        log.info("Send msg to bus:" + jsonObject.toJSONString());
        try{
            producer.send("order_pay_success",order.getBusType().trim() , JSONS.toBytes( jsonObject ) );
        }catch (Exception e){
            emailService.sendEmail("wenzuojing1@zy.com" ,"在线支付发送mq消息失败" , jsonObject.toJSONString() ,null ,null );
        }
    }


    @Override
    public PayOrder findHadPaidPayOrderByBusId(Long busId) {
        Example<PayOrder> example=PayOrder.createExample();
        Example.Criteria criteria=example.createCriteria();
        criteria.andEqualTo("busId",busId).andEqualTo("status" ,1 );
        return this.findOneByExample(example);
    }


    @Override
    public void updateBusHandleTime(Long payOrderId) {
        PayOrder payOrder = new PayOrder();
        payOrder.setPayOrderId(payOrderId);
        payOrder.setBusHandleTime(new Date());
        updateSelectiveById(payOrder);
    }

    @Override
    public boolean isPaid(Long busId) {
        PayOrder payOrder = findHadPaidPayOrderByBusId(busId);
        if(payOrder != null ){
            return true ;
        }
        return false ;
    }

    @Override
    public void sendPaySuccessEvent(Long payOrderId) {
        PayOrder payOrder = findById(payOrderId);
        if(payOrder.getStatus() == Constants.PAY_ORDER_STATUS_OF_PAID ){
            sendPaySuccessEvent(payOrder.getChannelTransactionNo(), payOrder);
        }else{
            throw new BusException("The status is not paid");
        }
    }
}